﻿using System;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

using Game.Command;
using Game.Controller;
using Game.Map;
using Game.Map.Extensions;
using Game.Objects;

namespace Game.Surface
{
    public class SurfaceTopField : AbstractField
    {
        readonly Polygon _Border = new Polygon();
        readonly DrawingGroup _DrawingGroup = new DrawingGroup();
        
        bool _DisplayedVehicle;
        bool _DisplayedTerrain;
        bool _DisplayedCommand;
        bool _DisplayedObject;

        public SurfaceTopField(
            IMapFieldView field,
            AbstractField cloud)
            : base(field)
        {
            _Border.Stroke = Brushes.Black;
            StrokeThickness = 1;
            foreach (var p in GetPoints(Size - 0.6))
            {
                _Border.Points.Add(p);
            }
            Content = _Border;
            
            field.VehicleX().VehicleAssigned += (source, args) =>
                                         {
                                             if (args.MapField.VehicleX().Vehicle != null)
                                             {
                                                 args.MapField.VehicleX().Vehicle.Movement.Changed += (source2, args2) =>
                                                 {
                                                     UpdateBitmap(field);
                                                 };
                                             }
                                             SetScale(this, 1);
                                             UpdateBitmap(field);
                                         };
            field.VehicleX().VehicleChanged += (source, args) =>
                                         {
                                             UpdateBitmap(field, true);
                                         };

            field.ObjectX().ObjectAssigned += (source, args) =>
                                        {
                                            SetScale(this, 1);
                                            UpdateBitmap(field);
                                        };
            
            field.ObjectX().PlayerChanged += (source, args) =>
                                        {
                                            UpdateBitmap(field, true);
                                        };
            
            field.CommandX().CommandAssigned += (source, args) => UpdateBitmap(field);

            field.Changed += (source, args) => UpdateBitmap(field);
            field.ViewX().Changed += (source, args) => UpdateBitmap(field);
            
            cloud.MouseEnter += (source, args) => GameSelect();
            cloud.MouseLeave += (source, args) => GameUnselect();

            cloud.MouseEnter += (source, args) => MakeLarge();
            cloud.MouseLeave += (source, args) => MakeSmall();
        }

        DrawingGroup DrawingGroup
        {
            get { return _DrawingGroup; }
        }
        
        Brush Stroke
        {
            get { return _Border.Stroke; }
            set { _Border.Stroke=value; }
        }
        
        double StrokeThickness
        {
            get { return _Border.StrokeThickness; }
            set { _Border.StrokeThickness=value; }
        }
        
        public void GameSelect()
        {
            Stroke = Brushes.Blue;
            StrokeThickness = 3;
        }

        public void GameUnselect()
        {
            Stroke = Brushes.Black;
            StrokeThickness = 1;
        }

        protected override bool CanZoom()
        {
            if (!MapField.IsVisible)
            {
                return false;
            }
            
            if (MapField.VehicleX().Vehicle == null)
            {
                return false;
            }

            if (MapField.VehicleX().Vehicle != null)
            {
                if (MapField.VehicleX().Vehicle.Owner == Common.AiPlayer.Player)
                {
                    return false;
                }

                if (MapField.VehicleX().Vehicle.Movement.Value <= 0)
                {
                    return false;
                }
            }

            return true;
        }

        protected override void UpdateBitmap(
            IMapFieldView field,
            bool force)
        {
            bool displayedTerrain = field.IsVisible;
            Vehicle vehicle = VehicleExtensionHelper.VehicleX(field).Vehicle;
            bool displayedVehicle = (vehicle != null);
            GameCommand command = CommandExtensionHelper.CommandX(field).Command;
            bool displayedCommand = (command != null);
            GameObject obj = GameObjectExtensionHelper.ObjectX(field).GameObject;
            bool displayedObject = (obj != null);
            
            if (_DisplayedVehicle == displayedVehicle &&
                _DisplayedCommand == displayedCommand &&
                _DisplayedObject == displayedObject &&
                _DisplayedTerrain == displayedTerrain &&
                Decorators.Count == 0 &&
                force == false)
            {
                return;
            }
            
            _DisplayedTerrain = displayedTerrain;
            _DisplayedVehicle = displayedVehicle;
            _DisplayedCommand = displayedCommand;
            _DisplayedObject = displayedObject;
            
            RenderTargetBitmap target = new RenderTargetBitmap(
               300, 300, 96, 96, PixelFormats.Pbgra32);
            
            if (displayedTerrain)
            {
                SurfaceFieldRenderer.RenderTerrain(field, target);
                
                if (displayedObject)
                {
                    SurfaceFieldRenderer.RenderMapObject(field, target);
                }
                if (displayedVehicle)
                {
                    SurfaceFieldRenderer.RenderVehicle(vehicle, target);
                }
                if (displayedCommand)
                {
                    SurfaceFieldRenderer.RenderCommandImage(field, target);
                }
            }
            
            Brush brush = new ImageBrush(target);
            brush = Decorators.Aggregate(brush, (current, d) => d.Decorate(current));
            Fill = brush;
        }

        void MakeLarge()
        {
            if (!CanZoom())
            {
                SetScale(this, 1);
                return;
            }

            int z = GameCanvas.GetZIndex(this);
            GameCanvas.SetZIndex(this, ++z);
            StartAutomation(1.0, 1.3, 0.2);
        }

        void MakeSmall()
        {
            if (!CanZoom())
            {
                if (GetScale(this) > 1)
                {
                    StartAutomation(1.3, 1.0, 1);
                }

                return;
            }

            GameCanvas.SetZIndex(this, 0);
            StartAutomation(1.3, 1.0, 1);
        }

        public void StartAutomation(double start, double end, double time)
        {
            var a = new DoubleAnimation { From = start, To = end };

            var duration = new Duration(TimeSpan.FromSeconds(time));
            a.EasingFunction = new ExponentialEase();
            a.Duration = duration;

            var sb = new Storyboard { Duration = duration };
            sb.Children.Add(a);

            Storyboard.SetTarget(a, this);
            Storyboard.SetTargetProperty(a, new PropertyPath("Scale"));

            sb.Begin();
        }

    }
}

